package com.hidataplus.hadoop.tezui;

import org.apache.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ProxyFilter implements Filter {

    public static Logger logger = LoggerFactory.getLogger(ProxyFilter.class);


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        Boolean checkUserPermission = Config.getUserPermissionPageCheck();
        logger.info("checkUserPermission:" + checkUserPermission);

        HttpServletRequest req = (HttpServletRequest)servletRequest;
        HttpServletResponse resp = (HttpServletResponse)servletResponse;

        String userName = servletRequest.getParameter("user.name");
        logger.info("request参数：user.name:" + userName);
        if(userName == null || userName.trim().equals(""))
        {
            userName = Config.getUserName(); //如果前端未传值，则取默认值，后续增加从认证框架里读取，并存放于session中
        }
        HttpSession httpSession = req.getSession();
        User user = (User) httpSession.getAttribute("user");
        if(user!=null){
            userName = user.getUsername();
            logger.info("current login user:" + userName);
        }
        logger.info("final userName(user.name): " + userName);

        if(checkUserPermission){
            String adminUsers =  Config.getUserAdmin();
            logger.info("adminUsers(user.admin): " + adminUsers);
            String[] adminUserArray = Config.getUserAdmin().split(",");
            for(String adminUser : adminUserArray){
                if(userName.equals(adminUser)){
                    checkUserPermission = false; //如果是管理员，则不用加过滤用户参数
                }
            }
        }

        String ip = req.getRemoteAddr();
        String uri = req.getRequestURI();



        String relateUrl = uri.replace(req.getContextPath(),"");
        logger.info("relateUrl " + relateUrl);


        Map map = req.getParameterMap();
        Set<String> keySet = map.keySet();
        StringBuffer sbQueryParams = new StringBuffer("");
        Map<String,String> keyValueMap = new HashMap<String,String>();

        //特殊参数处理
        if (checkUserPermission && relateUrl.equals("/proxy/ats/ws/v1/timeline/TEZ_DAG_ID")) {
            boolean tezDagIdUserParamsAdded = false;
            boolean tezDagIdUserParamsHasPrimaryFilter = false;
            boolean tezDagIdUserParamsHasSecondaryFilter = false;
            boolean tezDagIdUserParamsHasDagName = false;

            for (String key : keySet) {
//                String keyValue = URLEncoder.encode(req.getParameter(key), "UTF-8");

                String keyValue = req.getParameter(key);
                String newValue = keyValue;
                if (checkUserPermission)
                    if (key.equals("primaryFilter")) {
                        if (keyValue.contains("user:")) {
                            newValue = "user:\"" + userName + "\"";
                            tezDagIdUserParamsAdded = true;
                            logger.info("rewrite pararm(" + key + ") value(" + keyValue + ") to : " + newValue);
                        }
                        tezDagIdUserParamsHasPrimaryFilter = true;
                        logger.info("primaryFilter key value : " + newValue);
                        tezDagIdUserParamsHasDagName = keyValue.contains("dagName:"); //%3A 为:

                    } else if (key.equals("secondaryFilter")) {
                        if (keyValue.contains("user:")) {
                            int startIndex = keyValue.indexOf("user:\"")+ "user:\"".length();;
                            int endIndex = keyValue.indexOf("\"", startIndex);
                            newValue = keyValue.substring(0, startIndex)  + userName + keyValue.substring(endIndex);
                            tezDagIdUserParamsAdded = true;
                            logger.info("rewrite pararm(" + key + ") value(" + keyValue + ") to : " + newValue);
                        }
                        tezDagIdUserParamsHasSecondaryFilter = true;
                    }
                keyValueMap.put(key, newValue);
            }

            if (checkUserPermission && !tezDagIdUserParamsAdded) {
                if (tezDagIdUserParamsHasPrimaryFilter) {
                    if (tezDagIdUserParamsHasDagName) {
                        //如果primay不好含dagName
                        String newValue;
                        if (tezDagIdUserParamsHasSecondaryFilter) {
                            //如果econdaryFilter包含其他参数
                            String oldValue =  keyValueMap.get("secondaryFilter");
                            newValue = "user:\"" + userName + "\"," + oldValue;
                            logger.info(" update secondaryFilter pararm(secondaryFilter) value ( " +oldValue + " : " + newValue);
                        } else {
                            //如果不包含SecondaryFilter，则新增
                            newValue = "user:\"" + userName + "\"";
                            logger.info("add secondaryFilter pararm(secondaryFilter) value : " + newValue);
                        }
                        keyValueMap.put("secondaryFilter", newValue);

                    } else {
                        //如果primay不包含dagName
                        String secondValue = keyValueMap.get("primaryFilter");
                        keyValueMap.put("secondaryFilter", secondValue);
                        logger.info("adjust primaryFilter to secondaryFilter");
                        String primaryValue = "user:\"" + userName + "\"";
                        keyValueMap.put("primaryFilter", primaryValue);
                    }
                } else {
                    //如果不包含PrimaryFilter，直接添加
                    String primaryValue = "user:\"" + userName + "\"";
                    keyValueMap.put("primaryFilter", primaryValue);
                    logger.info("only add primaryFilter");
                }
            }
        }
        else  if (checkUserPermission && relateUrl.equals("/proxy/ats/ws/v1/timeline/HIVE_QUERY_ID")) {
            boolean hiveQueryUserParamsAdded = false;
            boolean hiveQueryUserParamsHasPrimaryFilter = false;
            boolean hiveQueryUserParamsHasSecondaryFilter = false;
            boolean hiveQueryUserParamsHasDagName = false;

            for (String key : keySet) {
//                String keyValue = URLEncoder.encode(req.getParameter(key), "UTF-8");

                String keyValue = req.getParameter(key);
                String newValue = keyValue;
                if (checkUserPermission)
                    if (key.equals("primaryFilter")) {
                        if (keyValue.contains("requestuser:")) {
                            newValue = "requestuser:\"" + userName + "\"";
                            hiveQueryUserParamsAdded = true;
                            logger.info("rewrite pararm(" + key + ") value(" + keyValue + ") to : " + newValue);
                        }
                        hiveQueryUserParamsHasPrimaryFilter = true;
                        logger.info("primaryFilter key value : " + keyValue);
                        hiveQueryUserParamsHasDagName = keyValue.contains("DAG_ID:") || keyValue.contains("APP_ID:") ; //%3A 为:

                    } else if (key.equals("secondaryFilter")) {
                        if (keyValue.contains("requestuser:")) {
                            int startIndex = keyValue.indexOf("requestuser:\"") + "requestuser:\"".length();
                            int endIndex = keyValue.indexOf("\"", startIndex);
                            newValue = keyValue.substring(0, startIndex) + userName + keyValue.substring(endIndex);
                            hiveQueryUserParamsAdded = true;
                            logger.info("rewrite pararm(" + key + ") value(" + keyValue + ") to : " + newValue);
                        }
                        hiveQueryUserParamsHasSecondaryFilter = true;
                    }
                keyValueMap.put(key, newValue);
            }

            if (checkUserPermission && !hiveQueryUserParamsAdded) {
                if (hiveQueryUserParamsHasPrimaryFilter) {
                    if (hiveQueryUserParamsHasDagName) {
                        //如果primay不好含dagName
                        String newValue;
                        if (hiveQueryUserParamsHasSecondaryFilter) {
                            //如果econdaryFilter包含其他参数
                            String oldValue =  keyValueMap.get("secondaryFilter");
                            newValue = "requestuser:\"" + userName + "\"," + oldValue;
                            logger.info(" update secondaryFilter pararm(secondaryFilter) value ( " +oldValue + " : " + newValue);
                        } else {
                            //如果不包含SecondaryFilter，则新增
                            newValue = "requestuser:\"" + userName + "\"";
                            logger.info("add secondaryFilter pararm(secondaryFilter) value : " + newValue);
                        }
                        keyValueMap.put("secondaryFilter", newValue);

                    } else {
                        //如果primay不包含dagName
                        String secondValue = keyValueMap.get("primaryFilter");
                        keyValueMap.put("secondaryFilter", secondValue);
                        logger.info("adjust primaryFilter to secondaryFilter");
                        String primaryValue = "requestuser:\"" + userName + "\"";
                        keyValueMap.put("primaryFilter", primaryValue);
                    }
                } else {
                    //如果不包含PrimaryFilter，直接添加
                    String primaryValue = "requestuser:\"" + userName + "\"";
                    keyValueMap.put("primaryFilter", primaryValue);
                    logger.info("only add primaryFilter");
                }
            }
        }

        else{
            logger.info("nothing process ,just copy");
            //nothing process ,just copy
            for (String key : keySet) {

                String keyValue = req.getParameter(key);
                keyValueMap.put(key, keyValue);
            }
        }

        //拼接字符串
        keySet = keyValueMap.keySet();
        for (String key : keySet){
            String keyValue = URLEncoder.encode(keyValueMap.get(key), "UTF-8");
            sbQueryParams.append("&");
            sbQueryParams.append(key);
            sbQueryParams.append("=");
            sbQueryParams.append(keyValue);
        }



        String urlParams = "";
        if(sbQueryParams.length() > 0){
            urlParams= "?" + sbQueryParams.substring(1);
        }
//        String encodeUrl = URLEncoder.encode(url, "UTF-8");

        logger.info("request ip :" + ip);

        logger.info("request params :" + urlParams);

        HttpServletResponse response=(HttpServletResponse)servletResponse;

        if(uri.indexOf("/proxy/ats") > -1 ){
            logger.info("proxy ats url:" + uri);
            try {

                String requestUrl = Config.getYarnAtsUrl() + uri.substring(uri.indexOf("/proxy/ats/")+"/proxy/ats/".length())  +  urlParams ;
                logger.info("real ats url:" + requestUrl);

                String result  =  this.callRestUrlString(requestUrl,userName);
                writeResponse(response,200,result);

            } catch (URISyntaxException e) {
                e.printStackTrace();
            }

        }else if(uri.indexOf("/proxy/rm") > -1 ){
            logger.info("proxy rm url:" + uri);
            String requestUrl = Config.getYarnRmUrl() + uri.substring(uri.indexOf("/proxy/rm/")+"/proxy/rm/".length())  +  urlParams ;
            logger.info("real rm url:" + requestUrl);

            if(  uri.contains("cluster/app/application_") ){
                String yarnRmUrl = Config.getYarnRmUrl();
                String requestNewUrl = "";
                if(Config.getProxyKnoxEnable()){
                    String proxyKnoxUrl = Config.getProxyKnoxUrl();
                    String proxyKnoxYarnUrl = proxyKnoxUrl + "yarn/";
                    String yarnRmHostAndPort = yarnRmUrl.replace("http://","").replace("/","");
                    requestNewUrl = requestUrl.replace(yarnRmUrl,proxyKnoxYarnUrl).replace(yarnRmHostAndPort,proxyKnoxYarnUrl);
                }else{
//                    /tez-ui/proxy/rm/cluster/app/application_1672798783687_0002
                    requestNewUrl =  yarnRmUrl + uri.replace(req.getContextPath(),"").replace("/proxy/rm/","");
                }
                logger.info("redirect to :" + requestNewUrl);
                response.sendRedirect(requestNewUrl);
                return;
            }

            String result  = null;
            try {
                result = this.callRestUrlString(requestUrl,userName);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
            writeResponse(response,200,result);
        }

//        filterChain.doFilter(servletRequest,servletResponse);
        //下面这行代码就是放行
//        filterChain.doFilter(servletRequest,servletResponse);
        //System.out.println("对response进行过滤");
    }


    public String callRestUrlString(String url, String userName) throws URISyntaxException, IOException {

        String  resultContent = "";
        Boolean kerberosEnable = Config.getKerberosEnable();
        if(kerberosEnable){
            logger.info("kerberos enabled!");
            String principal = Config.getKerberosPrincipal();
            String keytab = Config.getKerberosKeytab();
            String krb5Conf = Config.getKerberosKrb5conf();
            Boolean debug = Config.getKerberosDebug();
            RequestKerberosUrlUtils requestKerberosUrlUtils = new  RequestKerberosUrlUtils(principal,keytab,krb5Conf,debug);
            resultContent =  requestKerberosUrlUtils.callRestUrlString(url,userName);

        }else{
            RequestUrlUtils requestUrlUtils = new  RequestUrlUtils();
            resultContent =  requestUrlUtils.callRestUrlString(url,userName);
        }

//        resultContent = getReplaceString(resultContent);


        return resultContent;
    }

//    //替换内容
//    private String getRedirectKnoxUrl(String orginUrl) {
//
//        String knoxUrl = orginUrl;
//        boolean knoxEnable = Config.getProxyKnoxEnable();
//        String knoxUrlPrefix = Config.getProxyKnoxUrl();
//        if(knoxEnable){
//            if(orginUrl.contains("cluster/app/application_")){
//                knoxUrl = knoxUrlPrefix + orginUrl.replace("http://","").replace("/proxy/knox","");
//            }else{
//
//            }
//        }
//
//        return knoxString;
//    }
//    //替换内容
//    private String getReplaceString(String orginString) {
//        boolean knoxEnable = Config.getProxyKnoxEnable();
//        logger.info("proxy.knox.enable:" + knoxEnable);
//        if(!knoxEnable){
//            return orginString;
//        }
//        String proxyOriginKeywords = Config.getProxyOriginKeywords();
//        logger.info("proxyOriginKeywords:" + proxyOriginKeywords);
//
//        if(!proxyOriginKeywords.equals("") ){
//            String[] proxyOriginKeywordsArray = proxyOriginKeywords.split(",");
//
//                for(int i=0; i< proxyOriginKeywordsArray.length; i++){
//                    logger.info("replace " + proxyOriginKeywordsArray[i] + " with " + "proxy/knox");
//                    orginString = orginString.replace(proxyOriginKeywordsArray[i] ,"proxy/knox");
//                }
//
//        }
//        return orginString;
//    }

    public  void writeResponse(HttpServletResponse response, int status, String json) {

        try {
            response.reset();//很重要
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "*");
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(status);
            response.getWriter().write(json);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void destroy() {

    }

}